﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace Dolly
{
	/// <summary>
	/// Class produces cloned enumerables
	/// </summary>
	/// <typeparam name="T">any object type</typeparam>
	public class CloneFactory<T> : ICloner<T>
	{
		private int _maxCloneOfOne = 64;
		private IEnumerable<T> _input;
		private Stack<ICloner<T>> cloners;
		private Dictionary<Guid, IEnumerable<T>> clones;
		private Stack<IEnumerable<T>> missMe;

		public CloneFactory(IEnumerable<T> input)
		{
			_input = input;
			cloners = new Stack<ICloner<T>>();
			missMe = new Stack<IEnumerable<T>>();
			clones = new Dictionary<Guid, IEnumerable<T>>();
		}

		/// <summary>
		/// Returns cloned enumerable
		/// </summary>
		/// <returns>mirror of input</returns>
		public IEnumerable<T> GetClone() 
		{
			if (cloners.Count == 0)
				cloners.Push(new Cloner<T>(_input)); 
			
			var isLast = 
				clones.Count > 0 && 
				clones.Count % (_maxCloneOfOne - 1) == 0;

			ICloner<T> cloner;
			var g = Guid.NewGuid();
			IEnumerable<T> result;
			if (!isLast)
			{
				cloner = cloners.Peek();
			}
			else
			{
				var lastCloneForCloner = cloners.Peek().GetClone();
				missMe.Push(lastCloneForCloner);
				cloners.Push(cloner = new Cloner<T>(lastCloneForCloner));
				g = Guid.NewGuid();
			}
			result = cloner.GetClone();
			clones.Add(g, result);
			return result;
		}

		public void AllowReading()
		{
			var reversedCloners = cloners.Reverse().ToList();
			foreach (var cloner in reversedCloners)
				cloner.AllowReading();
		}
	}
}
